unit FXMLLoader;

interface
uses
	XMLIntf, XMLDoc, FLogs, SysUtils, FBase;

procedure LoadXMLFile(path : string);

type
	tElement = string;
	pointType = (TOP, BOTTOM, LEFT, RIGHT, CENTER, TOPLEFT, BOTTOMLEFT, TOPRIGHT, BOTTOMRIGHT);

	PosType = Record
		x : integer;
  	y : integer;
	end;

	TexCoordType = Record
		top : integer;
		left : integer;
		bottom : integer;
  	right : integer;
	end;

	AnchorType = Record
		Point : pointType;
		RelativePoint : pointType;
		RelativeTo : tElement;
		Offset : PosType;
	end;

	ColorType = Record
		r : Float;
		g : Float;
		b : Float;
	End;

	FontStringType = Record
		Name : string;
		Hidden : boolean;
		Virtual : boolean;
		Size : integer;
		Anchor : AnchorType;
		Path : string;
		Text : string;
	end;

	TextureType = Record
		Name : string;
		Size : PosType;
		Anchor : AnchorType;
		Hidden : boolean;
		Virtual : boolean;
		Path : string;
		TexCoord : TexCoordType;
	end;

	ScriptsType = Record
		OnLoad : string;
		OnUpdate : string;
		OnClick : string;
		OnEnter : string;
		OnLeave : string;
		OnKeyUp : string;
		OnKeyDown : string;
	end;

	FrameTypeP = ^FrameType;
	FrameType = Record
		Name : string;
		Size : PosType;
		Anchor : AnchorType;
		EnableMouse : boolean;
		EnableKeyboard : boolean;
		Hidden : boolean;
		Virtual : boolean;
		Parent : FrameTypeP;

		Scripts : ScriptsType;
		Frames : array of FrameTypeP;
		FontStrings : array of FontStringType;
	end;

	NameRelList = array of Record
		name : string;
		frame : FrameTypeP;
	end;

	PNode = ^IXMLNode;

var
	UI : FrameType;

	XMLFunctionList : array[0..100] of procedure (Node : PNode);
	XMLTypeList : array[0..100] of string;
	FrameStack : array of FrameTypeP;

procedure initXMLLoader();

implementation
uses
	FGlWindow;

function Inc(var i : integer) : integer; overload; begin i := i + 1; Result := i; end;

procedure HandleNode(Node : PNode);
var
	i : integer;
begin
	for i := 0 to Length(XMLTypeList) - 1 do
		if Node.NodeName = XMLTypeList[i] then
			XMLFunctionList[i](Node);
end;

procedure ParseChild(Node : PNode);
var
	ChildNode : IXMLNode;
begin
	if Node.HasChildNodes then begin
		ChildNode := Node.ChildNodes.First;
		repeat
			HandleNode(@ChildNode);
			ChildNode := ChildNode.NextSibling;
		until ChildNode = nil;
	end;
end;

procedure HandleOnLoad(Node : PNode);
begin
	FrameStack[Length(FrameStack) - 1].Scripts.OnLoad := Node^.Text;
end;

procedure HandleOnUpdate(Node : PNode);
begin
	FrameStack[Length(FrameStack) - 1].Scripts.OnUpdate := Node^.Text;
end;

procedure HandleOnClick(Node : PNode);
begin
	FrameStack[Length(FrameStack) - 1].Scripts.OnClick := Node^.Text;
end;

procedure HandleOnEnter(Node : PNode);
begin
	FrameStack[Length(FrameStack) - 1].Scripts.OnEnter := Node^.Text;
end;

procedure HandleOnLeave(Node : PNode);
begin
	FrameStack[Length(FrameStack) - 1].Scripts.OnLeave := Node^.Text;
end;

procedure HandleOnKeyUp(Node : PNode);
begin
	FrameStack[Length(FrameStack) - 1].Scripts.OnKeyUp := Node^.Text;
end;

procedure HandleOnKeyDown(Node : PNode);
begin
	FrameStack[Length(FrameStack) - 1].Scripts.OnKeyDown := Node^.Text;
end;

procedure HandleFrame(Node : PNode);
var
	i, j : integer;
begin
	i := Length(FrameStack);
	j := 0;
	if i > 0 then begin
		j := Length(FrameStack[i-1].Frames);
		SetLength(FrameStack[i-1].Frames, j + 1);
		New(FrameStack[i-1].Frames[j]);
		FrameStack[i-1].Frames[j].Name := Node^.Attributes['name'];
	end;

	SetLength(FrameStack, i + 1);
	FrameStack[i] := FrameStack[i-1].Frames[j];
	ParseChild(Node);
	SetLength(FrameStack, i);
end;

procedure HandleScript(Node : PNode);
begin
	if Node.HasAttribute('file') then
		log(Node.Attributes['file']);
	if length(Node.Text) > 0 then
		Log(Node.Text);
end;

procedure LoadXMLFile(path : string);
var
	Node : IXMLNode;
	Frame : FrameType;
begin
	SetLength(FrameStack, 1);
	FrameStack[0] := @Ui;

	try
		GlWindow.Document.LoadFromFile(path);
		Node := GlWindow.Document.DocumentElement;
	except
		on E : Exception do begin
			Log('Error loading ' + path + ': ' + E.Message);
			exit;
		end;
	end;

	HandleNode(@Node);

	Frame := Ui;
end;

procedure initXMLLoader();
var
	i : integer;
begin
	i := -1;
	XMLTypeList[Inc(i)] := 'Ui';
	XMLFunctionList[i] := ParseChild;
	XMLTypeList[Inc(i)] := 'Frames';
	XMLFunctionList[i] := ParseChild;
	XMLTypeList[Inc(i)] := 'Scripts';
	XMLFunctionList[i] := ParseChild;

	XMLTypeList[Inc(i)] := 'Script';
	XMLFunctionList[i] := HandleScript;

	XMLTypeList[Inc(i)] := 'OnLoad';
	XMLFunctionList[i] := HandleOnLoad;
	XMLTypeList[Inc(i)] := 'OnUpdate';
	XMLFunctionList[i] := HandleOnUpdate;
	XMLTypeList[Inc(i)] := 'OnClick';
	XMLFunctionList[i] := HandleOnClick;
	XMLTypeList[Inc(i)] := 'OnEnter';
	XMLFunctionList[i] := HandleOnEnter;
	XMLTypeList[Inc(i)] := 'OnLeave';
	XMLFunctionList[i] := HandleOnLeave;
	XMLTypeList[Inc(i)] := 'OnKeyUp';
	XMLFunctionList[i] := HandleOnKeyUp;
	XMLTypeList[Inc(i)] := 'OnKeyDown';
	XMLFunctionList[i] := HandleOnKeyDown;


	XMLTypeList[Inc(i)] := 'Frame';
	XMLFunctionList[i] := HandleFrame;
end;

end.

